昨天稍微講了 同步
和 非同步
,而實際上 JavaScript 是怎麼做到非同步的,那就是今天的主體:事件循環(Event Loop)
。在這之前,要先來介紹整個瀏覽器環境中除了 JavaScript 本身外的兩大組成要素,分別是 Web APIs
和 Callback Queue(回調佇列)
。
我們在使用 JavaScript 的非同步程式碼時,其實是依靠一個稱為Web APIs
的酷東西,它是瀏覽器提供的一系列非同步操作Api,用於處理網絡請求、計時器、DOM 操作等。當使用 Web APIs(例如 setTimeout、fetch、XMLHttpRequest 等)執行非同步操作時,這些操作會在背景中運行,而不會阻塞 JavaScript 的執行;而當操作完成後,會將對應的 callback function(回調函式)
放入 Callback Queue
。
Callback Queue
,或稱Task Queue
,是一個先進先出(FIFO,先進先出)的資料結構,這裡存放來自 Web APIs
完成非同步操作後回傳的callback(回調函式)
。
這些放在佇列中的callback
會一直等待,直到適當的時機點被移出佇列。
這個時機點為 JavaScript 的的呼叫堆疊(call stack)
為空的時候(即當所有同步操作完成後),Callback Queue
中 callback
會一個一個依序被移出佇列並放入JavaScript的呼叫堆疊(call stack)
中執行。
只看文字或許不太明白,我們直接來看圖。 (圖片來源)
上圖是整個瀏覽器環境中整體的運作流程,可以明顯看到三大區塊:JS引擎
、Web APIs
、Callback Queue
。
先簡單分析上圖,先看左上,JavaScript 堆疊(Call Stack)最頂端的 setTimeout() 是非同步,因此它會被交給 WebApis
去處理,而 JS引擎
則會繼續執行 showText() ,就這樣一直執行堆疊中剩下的內容。
而另一邊當 WebApis
將 setTimeout() 處理完畢時,它會將「setTimeout() 對應的callback」放入 Callback Queue
,而不會被 JavaScript 立即執行。
回到JavaScript 堆疊(Call Stack)這邊,當呼叫堆疊內都執行完畢(堆疊為空時),就會從 Callback Queue
依序取出 callback 並執行。
另外,關於上圖 Callback Queue
中的 Macrotask
與 MicroTask
,是兩種非同步操作的類型,它們有不同的執行順序和優先級。這留到明天再談。
以下是以動圖的方式呈現的範例。 (圖片來源)
關於以上動圖的畫面,其實是一個叫做 Loupe 的網站,這個視覺化小工具,可以幫助我們了解 JavaScript 的Call Stack(呼叫堆疊)
、Web Apis
、Callback Queue(回調佇列)
如何互動的,讓我們可以更清楚 事件循環(Event Loop)
的運作過程。
另外 Loupe 網站中提到的影片「所以說event loop到底是什麼玩意兒?」中詳細介紹了 Event Loop
的運作
原理,更是非常值得一看。
那麼今天就到這邊,明天見~